<?php


namespace App\Service;

use AlibabaCloud\Cassandra\V20190101\DeleteBackupPlan;
use App\Constants\SettleAccessType;
use App\Model\Dao\ChannelInfoDao;
use App\Model\Dao\TradeTransDao;
use App\Model\Enum\OrderHandleStatusEnum;
use App\Model\Enum\OrderSettleStatusEnum;
use App\Model\Enum\TradeTrans\TradeTransSettleStatusEnum;
use App\Model\Enum\TradeTrans\TradeTransReviewStatusEnum;
use App\Model\Enum\TradeTrans\TradeTransTypeEnum;
use App\Utils\CustomUtils;
use Hyperf\Database\Query\Builder;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Arr;
use Swlib\SaberGM;

/**
 * Class TradeTransReviewService
 * 转账提现审核
 *
 * @package App\Service
 */
class TradeTransReviewService {

    /**
     * @Inject()
     * @var TradeTransDao
     */
    private $TradeTranDao;

    /**
     * @var SettleService
     * @Inject()
     */
    private $SettleService;

    /**
     * @var CommonBankService
     * @Inject()
     */
    private $CommonBankService;

    /**
     * @var ChannelInfoDao
     * @Inject()
     */
    private $ChannelInfoDao;

    /**
     * 提现/初审
     *
     * @param $param
     *
     * @return array
     * @throws \Exception
     */
    public function withdrawFirstReview ($param) {

        $isApprove = Arr::get($param, 'isApprove', false);

        // 读取提现申请记录
        $info = $this->TradeTranDao->getWhere(function (Builder $query) use ($param) {
            $query->where('type', TradeTransTypeEnum::WITHDRAW);
            $query->where('id', $param['id']);

            if (Arr::exists($param, "mchIdList") && !empty($param['mchIdList'])) {
                $query->whereIn('mchId', $param['mchIdList']);
            }
        });

        if (!$info) {
            throw new \Exception('未找到记录');
        }

        if ($info['settleStatus'] != TradeTransSettleStatusEnum::DONE) {
            throw new \Exception('出入账处理未完成');
        }

        if ($info['reviewStatus'] != TradeTransReviewStatusEnum::INIT) {
            throw new \Exception('不处于待审核状态');
        }

        $update = [
            'reviewBy'     => $param['createBy'],
            'reviewTime'   => time(),
            'reviewRemark' => $param['remark'],
        ];

        if ($isApprove) {
            // 初审通过
            $update['reviewStatus']   = TradeTransReviewStatusEnum::APPROVE;
            $update['transByApi']     = $param['useApi'];
            $update['transChannelId'] = $param['channelId'];
            $update['handleStatus']   = OrderHandleStatusEnum::FIRST_APPROVE;
        }
        else {
            // 初审驳回
            $update['reviewStatus'] = TradeTransReviewStatusEnum::REJECT;
            $update['handleStatus'] = OrderHandleStatusEnum::FIRST_REJECT;
        }

        $this->TradeTranDao->update($info['id'], $update);
        $this->TradeTranDao->update($info['id'], ['settleStatus' => TradeTransSettleStatusEnum::INIT]);

        $this->SettleService->addMq($info['mchId'], [
            'accessType'   => SettleAccessType::ACCESS_TYPE_WITHDRAW,
            'withdrawId'   => $info['id'],
            'handleStatus' => $update['handleStatus'],
            'mchNo'        => $info['mchNo'],
            'transNo'      => $info['transNo'],
        ]);

        $data = [];

        return CustomUtils::buildSuccess($data);
    }

    /**
     * 提现/复审
     *
     * @param $param
     *
     * @return array
     * @throws \Exception
     */
    public function withdrawSecondReview ($param) {

        $isApprove = Arr::get($param, 'isApprove', false);

        // 读取提现申请记录
        $info = $this->TradeTranDao->getWhere(function (Builder $query) use ($param) {
            $query->where('type', TradeTransTypeEnum::WITHDRAW);
            $query->where('id', $param['id']);

            if (Arr::exists($param, "mchIdList") && !empty($param['mchIdList'])) {
                $query->whereIn('mchId', $param['mchIdList']);
            }
        });

        if (!$info) {
            throw new \Exception('未找到记录');
        }
        if ($info['settleStatus'] != TradeTransSettleStatusEnum::DONE) {
            throw new \Exception('出入账处理未完成');
        }

        if ($info['reviewStatus'] != TradeTransReviewStatusEnum::APPROVE) {
            throw new \Exception('初审未通过');
        }

        if ($info['reReviewStatus'] != TradeTransReviewStatusEnum::INIT) {
            throw new \Exception('不处于待审核状态');
        }

        $update = [
            'reReviewBy'     => $param['createBy'],
            'reReviewTime'   => time(),
            'reReviewRemark' => $param['remark'],
            'settleStatus'   => TradeTransSettleStatusEnum::INIT,
        ];

        if ($isApprove) {
            // 复审通过
            $update['reReviewStatus'] = TradeTransReviewStatusEnum::APPROVE;
            $update['handleStatus']   = OrderHandleStatusEnum::SECOND_APPROVE;
        }
        else {
            // 复审驳回
            $update['reReviewStatus'] = TradeTransReviewStatusEnum::REJECT;
            $update['handleStatus']   = OrderHandleStatusEnum::SECOND_REJECT;
        }

        $updateBankStatus = null;

        try {
            Db::beginTransaction();

            $this->TradeTranDao->update($info['id'], $update);

            if ($isApprove && $info['transByApi']) {
                // API退款

                $re = $this->_callBankPay($info);

                if (CustomUtils::isSuccess($re)) {
                    $updateBankStatus = [
                        'bankTransStatus' => 1,
                        'bankTransTimes'  => Db::raw('`bankTransTimes` + 1'),
                    ];
                }
                else {
                    $updateBankStatus = [
                        'bankTransStatus' => 2,
                        'bankTransTimes'  => Db::raw('`bankTransTimes` + 1'),
                    ];
                    throw new \Exception($re['message']);
                }

            }

            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            throw $e;
        } finally {
            if (!!$updateBankStatus) {
                $this->TradeTranDao->update($info['id'], $updateBankStatus);
            }
        }

        // 结算系统处理
        $this->SettleService->addMq($info['mchId'], [
            'accessType'   => SettleAccessType::ACCESS_TYPE_WITHDRAW,
            'withdrawId'   => $info['id'],
            'handleStatus' => $update['handleStatus'],
            'mchNo'        => $info['mchNo'],
            'transNo'      => $info['transNo'],
        ]);

        $data = [];
        return CustomUtils::buildSuccess($data);
    }


    /**
     * 转帐/初审
     *
     * @param $param
     *
     * @return array
     * @throws \Exception
     */
    public function transferFirstReview ($param) {

        $isApprove = Arr::get($param, 'isApprove', false);

        // 读取提现申请记录
        $info = $this->TradeTranDao->getWhere(function (Builder $query) use ($param) {
            $query->where('type', TradeTransTypeEnum::TRANSFER);
            $query->where('id', $param['id']);

            if (Arr::exists($param, "mchIdList") && !empty($param['mchIdList'])) {
                $query->whereIn('mchId', $param['mchIdList']);
            }
        });

        if (!$info) {
            throw new \Exception('未找到记录');
        }

        if ($info['settleStatus'] != TradeTransSettleStatusEnum::DONE) {
            throw new \Exception('出入账处理未完成');
        }

        if ($info['reviewStatus'] != TradeTransReviewStatusEnum::INIT) {
            throw new \Exception('不处于待审核状态');
        }

        $update = [
            'reviewBy'     => $param['createBy'],
            'reviewTime'   => time(),
            'reviewRemark' => $param['remark'],
        ];

        if ($isApprove) {
            // 初审通过
            $update['reviewStatus']   = TradeTransReviewStatusEnum::APPROVE;
            $update['transByApi']     = $param['useApi'];
            $update['transChannelId'] = $param['channelId'];
            $update['handleStatus']   = OrderHandleStatusEnum::FIRST_APPROVE;

        }
        else {
            // 初审驳回
            $update['reviewStatus'] = TradeTransReviewStatusEnum::REJECT;
            $update['handleStatus'] = OrderHandleStatusEnum::FIRST_REJECT;
        }

        $this->TradeTranDao->update($info['id'], $update);

        $this->TradeTranDao->update($info['id'], ['settleStatus' => TradeTransSettleStatusEnum::INIT]);

        // 结算系统处理
        $this->SettleService->addMq($info['mchId'], [
            'accessType'   => SettleAccessType::ACCESS_TYPE_TRANS,
            'transId'      => $info['id'],
            'handleStatus' => $update['handleStatus'],
            'mchNo'        => $info['mchNo'],
            'transNo'      => $info['transNo'],
        ]);

        $data = [];

        return CustomUtils::buildSuccess($data);
    }

    /**
     * 转帐/复审
     *
     * @param $param
     *
     * @return array
     * @throws \Exception
     */
    public function transferSecondReview ($param) {

        $isApprove = Arr::get($param, 'isApprove', false);

        // 读取提现申请记录
        $info = $this->TradeTranDao->getWhere(function (Builder $query) use ($param) {
            $query->where('type', TradeTransTypeEnum::TRANSFER);
            $query->where('id', $param['id']);

            if (Arr::exists($param, "mchIdList") && !empty($param['mchIdList'])) {
                $query->whereIn('mchId', $param['mchIdList']);
            }
        });

        if (!$info) {
            throw new \Exception('未找到记录');
        }

        if ($info['settleStatus'] != TradeTransSettleStatusEnum::DONE) {
            throw new \Exception('出入账处理未完成');
        }

        if ($info['reviewStatus'] != TradeTransReviewStatusEnum::APPROVE) {
            throw new \Exception('初审未通过');
        }

        if ($info['reReviewStatus'] != TradeTransReviewStatusEnum::INIT) {
            throw new \Exception('不处于待审核状态');
        }

        $update = [
            'reReviewBy'     => $param['createBy'],
            'reReviewTime'   => time(),
            'reReviewRemark' => $param['remark'],
            'settleStatus'   => OrderSettleStatusEnum::INIT,
        ];

        if ($isApprove) {
            // 复审通过
            $update['reReviewStatus'] = TradeTransReviewStatusEnum::APPROVE;
            $update['handleStatus']   = OrderHandleStatusEnum::SECOND_APPROVE;
        }
        else {
            // 复审驳回
            $update['reReviewStatus'] = TradeTransReviewStatusEnum::REJECT;
            $update['handleStatus']   = OrderHandleStatusEnum::SECOND_REJECT;
        }

        $updateBankStatus = null;

        try {

            Db::beginTransaction();

            $this->TradeTranDao->update($info['id'], $update);

            if ($isApprove && $info['transByApi']) {
                // API转帐
                $re = $this->_callBankPay($info);

                if (CustomUtils::isSuccess($re)) {
                    $updateBankStatus = [
                        'bankTransStatus' => 1,
                        'bankTransTimes'  => Db::raw('`bankTransTimes` + 1'),
                    ];
                }
                else {
                    $updateBankStatus = [
                        'bankTransStatus' => 2,
                        'bankTransTimes'  => Db::raw('`bankTransTimes` + 1'),
                    ];
                    throw new \Exception($re['message']);
                }
            }

            Db::commit();

        } catch (\Throwable $e) {
            Db::rollBack();
            throw $e;
        } finally {
            if (!!$updateBankStatus) {
                $this->TradeTranDao->update($info['id'], $updateBankStatus);
            }
        }

        // 结算系统处理
        $this->SettleService->addMq($info['mchId'], [
            'accessType'   => SettleAccessType::ACCESS_TYPE_TRANS,
            'transId'      => $info['id'],
            'handleStatus' => $update['handleStatus'],
            'mchNo'        => $info['mchNo'],
            'transNo'      => $info['transNo'],
        ]);

        $data = [];

        return CustomUtils::buildSuccess($data);
    }

    /**
     * todo 上送银行网关 对接真实网关的时候要检查
     *
     * @param $tradeTransInfo
     *
     * @return array|mixed
     */
    protected function _callBankPay ($tradeTransInfo) {

        $channel = $this->ChannelInfoDao->getWhere(['id' => $tradeTransInfo['transChannelId'], 'status' => 1]);

        if (!$channel) {
            throw new \Exception('未找到支付通道');
        }

        $bankTransferParams              = json_decode($channel['params'], true);
        $bankTransferParams['channelNo'] = $channel['channelNo'];

        if ($tradeTransInfo['type'] == TradeTransTypeEnum::TRANSFER && $tradeTransInfo['extraType'] == 2) {
            return CustomUtils::buildSuccess([], '内部转账无需调用银行网关, 由结算出入账处理, 直接返回成功');
        }
        else {
            // 银行转帐或提现
            $bankTransferParams = array_merge($bankTransferParams, [
                'transNo'         => $tradeTransInfo['transNo'],
                'amount'          => $tradeTransInfo['targetAmount'],
                'currency'        => $tradeTransInfo['targetCurrency'],
                'bankAccountName' => $tradeTransInfo['bankAccountName'],
                'bankAccountNo'   => $tradeTransInfo['bankAccountNo'],
                'bankOpenBankNo'  => $tradeTransInfo['bankOpenBankNo'],
            ]);
        }

        // 无论是转账还是提现, 对银行来说都是向指定账户转账, 而商户账户转帐, 则是在银行网关定义了特殊的内部银行, 因此全都统一调用银行网关逻辑即可
        try {
            $re = $this->CommonBankService->doTransfer($bankTransferParams);
        } catch (\Throwable $e) {
            $re = CustomUtils::buildError($e->getMessage());
        }

        CustomUtils::xzxDebug("银行网关接口返回", $re);

        return $re;

    }
}
